home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / multimirror.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  8.4 KB  |  368 lines

  1. #include <assert.h>
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <GL/glut.h>
  6.  
  7. GLUquadricObj *cone, *base, *qsphere;
  8.  
  9. /* Some <math.h> files do not define M_PI... */
  10. #ifndef M_PI
  11. #define M_PI 3.14159265358979323846
  12. #endif
  13.  
  14. #ifndef __sgi
  15. #define trunc(x) ((double)((int)(x)))
  16. #endif
  17.  
  18. int draw_passes = 8;
  19.  
  20. int headsUp = 0;
  21.  
  22. typedef struct {
  23.   GLfloat verts[4][3];
  24.   GLfloat scale[3];
  25.   GLfloat trans[3];
  26. } Mirror;
  27.  
  28. Mirror mirrors[] = {
  29.   /* mirror on the left wall */
  30.   {{{-1., -.75, -.75}, {-1., .75, -.75}, {-1., .75, .75}, {-1, -.75, .75}},
  31.      {-1, 1, 1}, {2, 0, 0}},
  32.  
  33.   /* mirror on right wall */
  34.   {{{1., -.75, .75}, {1., .75, .75}, {1., .75, -.75}, {1., -.75, -.75}},
  35.      {-1, 1, 1}, {-2, 0, 0}},
  36. };
  37. int nMirrors = 2;
  38.  
  39. void init(void)
  40. {
  41.   static GLfloat lightpos[] = {.5, .75, 1.5, 1};
  42.  
  43.   glEnable(GL_DEPTH_TEST); 
  44.   glEnable(GL_LIGHTING);
  45.   glEnable(GL_LIGHT0);
  46.   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  47.  
  48.   glEnable(GL_CULL_FACE);
  49.  
  50.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  51.  
  52.   cone = gluNewQuadric();
  53.   qsphere = gluNewQuadric();
  54. }
  55.  
  56. void make_viewpoint(void)
  57. {
  58.   if (headsUp) {
  59.     float width = (1 + 2*(draw_passes/nMirrors)) * 1.25;
  60.     float height = (width / tan((30./360.) * (2.*M_PI))) + 1;
  61.  
  62.     glMatrixMode(GL_PROJECTION);
  63.     glLoadIdentity();
  64.     gluPerspective(60, 1, height - 3, height + 3);
  65.     gluLookAt(0, height, 0,
  66.           0, 0, 0, 
  67.           0, 0, 1);
  68.   } else {
  69.     glMatrixMode(GL_PROJECTION);
  70.     glLoadIdentity();
  71.     gluPerspective(60, 1, .01, 4 + 2*(draw_passes / nMirrors));
  72.     gluLookAt(-2, 0, .75, 
  73.           0, 0, 0, 
  74.           0, 1, 0);
  75.   }
  76.     
  77.   glMatrixMode(GL_MODELVIEW);
  78.   glLoadIdentity();
  79. }
  80.  
  81. void reshape(GLsizei w, GLsizei h) 
  82. {
  83.   glViewport(0, 0, w, h);
  84.   make_viewpoint();
  85. }
  86.  
  87. void draw_room(void)
  88. {
  89.   /* material for the walls, floor, ceiling */
  90.   static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
  91.  
  92.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
  93.  
  94.   glBegin(GL_QUADS);
  95.   
  96.   /* floor */
  97.   glNormal3f(0, 1, 0);
  98.   glVertex3f(-1, -1, 1);
  99.   glVertex3f(1, -1, 1);
  100.   glVertex3f(1, -1, -1);
  101.   glVertex3f(-1, -1, -1);
  102.  
  103.   /* ceiling */
  104.   glNormal3f(0, -1, 0);
  105.   glVertex3f(-1, 1, -1);
  106.   glVertex3f(1, 1, -1);
  107.   glVertex3f(1, 1, 1);
  108.   glVertex3f(-1, 1, 1);  
  109.  
  110.   /* left wall */
  111.   glNormal3f(1, 0, 0);
  112.   glVertex3f(-1, -1, -1);
  113.   glVertex3f(-1, 1, -1);
  114.   glVertex3f(-1, 1, 1);
  115.   glVertex3f(-1, -1, 1);
  116.  
  117.   /* right wall */
  118.   glNormal3f(-1, 0, 0);
  119.   glVertex3f(1, -1, 1);
  120.   glVertex3f(1, 1, 1);
  121.   glVertex3f(1, 1, -1);
  122.   glVertex3f(1, -1, -1);
  123.  
  124.   /* far wall */
  125.   glNormal3f(0, 0, 1);
  126.   glVertex3f(-1, -1, -1);
  127.   glVertex3f(1, -1, -1);
  128.   glVertex3f(1, 1, -1);
  129.   glVertex3f(-1, 1, -1);
  130.  
  131.   /* back wall */
  132.   glNormal3f(0, 0, -1);
  133.   glVertex3f(-1, 1, 1);
  134.   glVertex3f(1, 1, 1);
  135.   glVertex3f(1, -1, 1);
  136.   glVertex3f(-1, -1, 1);
  137.   glEnd();
  138. }
  139.  
  140. void draw_cone(void)
  141. {
  142.   static GLfloat cone_mat[] = {0.f, .5f, 1.f, 1.f};
  143.  
  144.   glPushMatrix();
  145.   glTranslatef(0, -1, 0);
  146.   glRotatef(-90, 1, 0, 0);
  147.  
  148.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  149.  
  150.   gluCylinder(cone, .3, 0, 1.25, 20, 1);
  151.  
  152.   glPopMatrix();
  153. }
  154.  
  155. void draw_sphere(GLdouble secs)
  156. {
  157.   static GLfloat sphere_mat[] = {1.f, .5f, 0.f, 1.f};
  158.   GLfloat angle;
  159.  
  160.   /* one revolution every 10 seconds... */
  161.   secs = secs - 10.*trunc(secs / 10.);
  162.   angle = (secs/10.) * (360.);
  163.  
  164.   glPushMatrix();
  165.   glTranslatef(0, -.3, 0);
  166.   glRotatef(angle, 0, 1, 0);
  167.   glTranslatef(.6, 0, 0);
  168.  
  169.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  170.   gluSphere(qsphere, .3, 20, 20);
  171.  
  172.   glPopMatrix();
  173. }
  174.  
  175. GLdouble get_secs(void)
  176. {
  177.   return glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  178. }
  179.  
  180. void draw_mirror(Mirror *m)
  181. {
  182.   glBegin(GL_QUADS);
  183.   glVertex3fv(m->verts[0]);
  184.   glVertex3fv(m->verts[1]);
  185.   glVertex3fv(m->verts[2]);
  186.   glVertex3fv(m->verts[3]);
  187.   glEnd();
  188. }
  189.  
  190. /* A note on matrix management:  it would be easier to use push and
  191.  * pop to save and restore the matrices, but the projection matrix stack
  192.  * is very shallow, so we just undo what we did.  In the extreme this
  193.  * could lead to mathematic error. */
  194.  
  195. GLenum reflect_through_mirror(Mirror *m, GLenum cullFace)
  196. {
  197.   GLenum newCullFace = ((cullFace == GL_FRONT) ? GL_BACK : GL_FRONT);
  198.  
  199.   glMatrixMode(GL_PROJECTION);
  200.   glScalef(m->scale[0], m->scale[1], m->scale[2]); 
  201.   glTranslatef(m->trans[0], m->trans[1], m->trans[2]); 
  202.   glMatrixMode(GL_MODELVIEW);
  203.  
  204.   /* must flip the cull face since reflection reverses the orientation
  205.    * of the polygons */
  206.   glCullFace(newCullFace);
  207.  
  208.   return newCullFace;
  209. }
  210.  
  211. void undo_reflect_through_mirror(Mirror *m, GLenum cullFace)
  212. {
  213.   glMatrixMode(GL_PROJECTION);
  214.   glTranslatef(-m->trans[0], -m->trans[1], -m->trans[2]);
  215.   glScalef(1./m->scale[0], 1./m->scale[1], 1./m->scale[2]);
  216.   glMatrixMode(GL_MODELVIEW);
  217.  
  218.   glCullFace(cullFace);
  219. }
  220.  
  221. void draw_scene(GLdouble secs, int passes, GLenum cullFace, 
  222.         GLuint stencilVal, GLuint mirror)
  223. {
  224.   GLenum newCullFace;
  225.   int passesPerMirror, passesPerMirrorRem;
  226.   unsigned int curMirror, drawMirrors;
  227.   int i;
  228.  
  229.   /* one pass to draw the real scene */
  230.   passes--;
  231.  
  232.   /* only draw in my designated locations */
  233.   glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);
  234.  
  235.   /* draw things which may obscure the mirrors first */
  236.   draw_sphere(secs);
  237.   draw_cone();
  238.  
  239.   /* now draw the appropriate number of mirror reflections.  for
  240.    * best results, we perform a depth-first traversal by allocating
  241.    * a number of passes for each of the mirrors. */
  242.   if (mirror != 0xffffffff) {
  243.     passesPerMirror = passes / (nMirrors - 1);
  244.     passesPerMirrorRem = passes % (nMirrors - 1);
  245.     if (passes > nMirrors - 1) drawMirrors = nMirrors - 1;
  246.     else drawMirrors = passes;
  247.   } else {
  248.     /* mirror == -1 means that this is the initial scene (there was no 
  249.      * mirror) */
  250.     passesPerMirror = passes / nMirrors;
  251.     passesPerMirrorRem = passes % nMirrors;
  252.     if (passes > nMirrors) drawMirrors = nMirrors;
  253.     else drawMirrors = passes;
  254.   }
  255.   for (i = 0; drawMirrors > 0; i++) {
  256.     curMirror = i % nMirrors;
  257.     if (curMirror == mirror) continue;
  258.     drawMirrors--;
  259.  
  260.     /* draw mirror into stencil buffer but not color or depth buffers */
  261.     glColorMask(0, 0, 0, 0);
  262.     glDepthMask(0);
  263.     glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 
  264.     draw_mirror(&mirrors[curMirror]);
  265.     glColorMask(1, 1, 1, 1);
  266.     glDepthMask(1);
  267.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  268.  
  269.     /* draw reflected scene */
  270.     newCullFace = reflect_through_mirror(&mirrors[curMirror], cullFace);
  271.     if (passesPerMirrorRem) {
  272.       draw_scene(secs, passesPerMirror + 1, newCullFace, stencilVal + 1, 
  273.          curMirror);      
  274.       passesPerMirrorRem--;
  275.     } else {
  276.       draw_scene(secs, passesPerMirror, newCullFace, stencilVal + 1, 
  277.          curMirror);
  278.     }
  279.     undo_reflect_through_mirror(&mirrors[curMirror], cullFace);
  280.  
  281.     /* back to our stencil value */
  282.     glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff);    
  283.   }
  284.  
  285.   draw_room(); 
  286. }
  287.  
  288. void draw(void)
  289. {
  290.   GLenum err;
  291.   GLfloat secs = get_secs();
  292.   
  293.   glDisable(GL_STENCIL_TEST);
  294.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  295.   
  296.   if (!headsUp) glEnable(GL_STENCIL_TEST);
  297.   draw_scene(secs, draw_passes, GL_BACK, 0, (unsigned)-1);
  298.   glDisable(GL_STENCIL_TEST);
  299.  
  300.   if (headsUp) {
  301.     /* draw a red floor on the original scene */
  302.     glDisable(GL_LIGHTING);
  303.     glBegin(GL_QUADS);
  304.     glColor3f(1, 0, 0);
  305.     glVertex3f(-1, -.95, 1);
  306.     glVertex3f(1, -.95, 1);
  307.     glVertex3f(1, -.95, -1);
  308.     glVertex3f(-1, -.95, -1);    
  309.     glEnd();
  310.     glEnable(GL_LIGHTING);
  311.   }
  312.  
  313.   err = glGetError();
  314.   if (err != GL_NO_ERROR) printf("Error:  %s\n", gluErrorString(err));
  315.   
  316.   glutSwapBuffers(); 
  317. }
  318.  
  319. /* ARGSUSED1 */
  320. void key(unsigned char key, int x, int y)
  321. {
  322.   switch(key) {
  323.   case '.':  case '>':  case '+':  case '=':
  324.     draw_passes++;
  325.     printf("Passes = %d\n", draw_passes);
  326.     make_viewpoint();
  327.     break;
  328.   case ',':  case '<':  case '-':  case '_':
  329.     draw_passes--;
  330.     if (draw_passes < 1) draw_passes = 1;
  331.     printf("Passes = %d\n", draw_passes);
  332.     make_viewpoint();
  333.     break;
  334.   case 'h':  case 'H':
  335.     /* heads up mode */
  336.     headsUp = (headsUp == 0);
  337.     make_viewpoint();
  338.     break;
  339.   case 27:
  340.     exit(0);
  341.   }
  342. }
  343.  
  344. #define MIN_COLOR_BITS 4
  345. #define MIN_DEPTH_BITS 8
  346.  
  347. main(int argc, char *argv[])
  348. {
  349.     glutInit(&argc, argv);
  350.     glutInitWindowSize(256, 256);
  351.     glutInitWindowPosition(0, 0);
  352.     if (argc > 1) {
  353.       glutInitDisplayString("samples stencil>=3 rgb depth");
  354.     } else { 
  355.       glutInitDisplayString("samples stencil>=3 rgb double depth");
  356.     }
  357.     glutCreateWindow(argv[0]);
  358.     glutDisplayFunc(draw);
  359.     glutIdleFunc(draw);
  360.     glutKeyboardFunc(key);
  361.     glutReshapeFunc(reshape);
  362.     init();
  363.  
  364.     glutMainLoop();
  365.     return 0;
  366. }
  367.  
  368.